/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 adv_object_flag.cpp

	$Header: /heroes4/adv_object_flag.cpp $

	$NoKeywords: $

 ************************************************************************/

#include "precompiled.h"
#include "adv_object_flag.h"

#include "animation.h"
#include "animation_cache.h"
#include "enum_operations.h"
#include "player_color.h"

// --------------------------------------------------------------------------
// Unnamed namespace
// --------------------------------------------------------------------------

namespace
{

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	t_cached_ptr< t_animation > get_flag_animation( t_player_color color )
	{
		assert( color >= 0 && color < k_player_color_count );

		static t_animation_cache flag_animation_cache_array[ k_player_color_count ] =
		{
			t_animation_cache( "flags.red" ),
			t_animation_cache( "flags.blue" ),
			t_animation_cache( "flags.green" ),
			t_animation_cache( "flags.orange" ),
			t_animation_cache( "flags.purple" ),
			t_animation_cache( "flags.teal" ),
			t_animation_cache( "flags.gray" ),
		};

		return flag_animation_cache_array[ color ].get();
	}

	// --------------------------------------------------------------------------
	// --------------------------------------------------------------------------
	t_screen_point get_base_point( t_animation const & animation )
	{
		t_screen_rect rect = animation.get_rect();
		t_screen_point result = animation.get_base_point();
		if ( !animation.x_is_valid() )
			result.x = rect.left + ( rect.right - rect.left ) / 2;
		if ( !animation.y_is_valid() )
			result.y = rect.top + ( rect.bottom - rect.top ) / 2;
		return result;
	}

} // Unnamed namespace

// --------------------------------------------------------------------------
// t_adv_object_flag members
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_screen_rect const & t_adv_object_flag::get_flag_extent()
{
	static t_screen_rect flag_extent;
	static bool initialized = false;
	if ( !initialized )
	{
		t_player_color color = t_player_color( 0 );
		t_cached_ptr< t_animation > flag_animation_ptr = get_flag_animation( color );
		flag_extent = flag_animation_ptr->get_rect() - get_base_point( *flag_animation_ptr );

		for ( enum_incr( color ); color < k_player_color_count; enum_incr( color ) )
		{
			flag_animation_ptr = get_flag_animation( color );
			t_screen_rect color_flag_extent =
				flag_animation_ptr->get_rect() - get_base_point( *flag_animation_ptr );
			flag_extent = get_extent( flag_extent, color_flag_extent );
		}

		initialized = true;
	}

	return flag_extent;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_adv_object_flag::t_adv_object_flag(
	t_player_color			color,
	t_screen_point const &	offset,
	int						depth_offset )
	:	m_animation_ptr( get_flag_animation( color ) ),
		m_color( color ),
		m_base_point( get_base_point( *m_animation_ptr ) ),
		m_offset( offset ),
		m_depth_offset( depth_offset ),
		m_time_offset( pick_time_offset() )
{
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_adv_object_flag::~t_adv_object_flag()
{
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
int t_adv_object_flag::compute_frame( t_uint32 time ) const
{
	t_animation const & animation = *m_animation_ptr;
	return ( ( time + m_time_offset ) / animation.get_frame_delay() ) % animation.get_frame_count();
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
void t_adv_object_flag::draw_to(
	int						frame_num,
	t_screen_rect const &	source_rect,
	t_abstract_bitmap16 &	dest,
	t_screen_point const &	dest_point,
	int						alpha ) const
{
	assert( frame_num >= 0 && frame_num < m_animation_ptr->get_frame_count() );
	assert( m_animation_ptr->get_frame( frame_num ) != 0 );

	t_screen_point offset = m_offset - m_base_point;

	t_screen_rect adjusted_source_rect = source_rect - offset;

	t_bitmap_layer const & frame = *m_animation_ptr->get_frame( frame_num );
	t_screen_rect frame_rect = frame.get_rect();

	if ( !intersect( adjusted_source_rect, frame_rect ) )
		return;

	adjusted_source_rect = intersection( adjusted_source_rect, frame_rect );

	frame.draw_to(
		adjusted_source_rect,
		dest,
		dest_point + offset + adjusted_source_rect.top_left(),
		alpha );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
void t_adv_object_flag::draw_to(
	int						frame_num,
	t_abstract_bitmap16 &	dest,
	t_screen_point const &	dest_point ) const
{
	assert( frame_num >= 0 && frame_num < m_animation_ptr->get_frame_count() );
	assert( m_animation_ptr->get_frame( frame_num ) != 0 );

	m_animation_ptr->get_frame( frame_num )->draw_to(
		dest,
		dest_point + m_offset - m_base_point );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
int t_adv_object_flag::get_depth_offset() const
{
	return m_depth_offset;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
int t_adv_object_flag::get_frame_count() const
{
	return m_animation_ptr->get_frame_count();
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_screen_rect t_adv_object_flag::get_rect() const
{
	static t_screen_rect const & k_flag_extent = get_flag_extent();
	return k_flag_extent + m_offset;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_screen_rect t_adv_object_flag::get_rect( int frame_num ) const
{
	assert( frame_num >= 0 && frame_num < m_animation_ptr->get_frame_count() );
	assert( m_animation_ptr->get_frame( frame_num ) != 0 );
	return m_animation_ptr->get_frame( frame_num )->get_rect() + m_offset - m_base_point;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_adv_object_flag::hit_test(
	int						frame_num,
	t_screen_point const &	point ) const
{
	assert( frame_num >= 0 && frame_num < m_animation_ptr->get_frame_count() );
	assert( m_animation_ptr->get_frame( frame_num ) != 0 );

	return m_animation_ptr->get_frame( frame_num )->contains( point - m_offset + m_base_point );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_adv_object_flag::is_underlay() const
{
	return false;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
void t_adv_object_flag::set_color( t_player_color new_color )
{
	assert( new_color >= 0 && new_color < k_player_color_count );
	if ( new_color != m_color )
	{
		m_animation_ptr = get_flag_animation( new_color );
		m_color = new_color;
		m_base_point = get_base_point( *m_animation_ptr );
	}
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
t_uint32 t_adv_object_flag::pick_time_offset() const
{
	t_animation const & animation = *m_animation_ptr;
	return rand() % ( animation.get_frame_count() * animation.get_frame_delay() );
}
